﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System.Net;
using System;
using System.IO;
using Game.Protocol;
using Google.Protobuf;
public class TcpNetwork  {
    private Socket _socket;
    private byte[] _ReceiveBuffer = new byte[1024];
    private List<byte> _Cache = new List<byte>();
    private bool isReading = false;
    private static readonly object networkLock = new object();
    public TcpNetwork(string ip="127.0.0.1",int port = 25510) {
        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
        IPAddress ipAddr = IPAddress.Parse(ip);
        IPEndPoint ipEndP = new IPEndPoint(ipAddr, port);
        _socket.BeginConnect(ipEndP, new AsyncCallback(ConnectCallBack),this._socket);

    }

    void ConnectCallBack(System.IAsyncResult result)
    {

        Socket tempSocket = result.AsyncState as Socket;
        if (tempSocket.Connected) { 
            tempSocket.BeginReceive(_ReceiveBuffer, 0, _ReceiveBuffer.Length, SocketFlags.None, ReceiveCallback, tempSocket);
        }
    }

    private void ReceiveCallback(IAsyncResult asyncResult)
    {
        Socket socket = asyncResult.AsyncState as Socket;
        int length = socket.EndReceive(asyncResult);
        byte[] buffer = new byte[length];
        Buffer.BlockCopy(_ReceiveBuffer, 0, buffer, 0, buffer.Length);
        _Cache.AddRange(buffer);
        if (!isReading)
        {
            isReading = true;
            OnDate();
        }
        socket.BeginReceive(_ReceiveBuffer, 0, _ReceiveBuffer.Length, SocketFlags.None, ReceiveCallback, socket);
    }

    private void OnDate()
    {
        byte[] decodeBuffer = GetDecodeBuffer();
        PackageHead head = PackageHead.Parser.ParseFrom(decodeBuffer);
        if (head != null)
        {
            NetManager.Instance.MsgDispatcher.Dispatch(head.Type,head.Area,head.Command, decodeBuffer);
        }
        else
        {
            isReading = false;
            return;
        }

        OnDate();
    }

    protected byte[] GetDecodeBuffer() {
        if (_Cache.Count < 4)
        {
            return null;
        }
        MemoryStream ms = new MemoryStream(_Cache.ToArray());
        BinaryReader br = new BinaryReader(ms);

        int length = br.ReadInt32();
        if (length > ms.Length - ms.Position)
        {
            return  null;
        }
        byte[] buffer = new byte[length];
        buffer = br.ReadBytes(buffer.Length);
        _Cache.Clear();
        _Cache.AddRange(br.ReadBytes((int)(ms.Length - ms.Position)));
        ms.Close();
        br.Close();
        return buffer;
    }

    public void SendMessage(IMessage pbIMessage)
    {
        
        byte[] sendBuffer = pbIMessage.ToByteArray();
        SendMessage(sendBuffer);
    }

    public void SendMessage(byte[] sendBuffer)
    {
        try
        {
            _socket.BeginSend(sendBuffer, 0, sendBuffer.Length, SocketFlags.None, SendCallback, sendBuffer);

        }
        catch (SocketException e)
        {

        }

    }

    private void SendCallback(IAsyncResult asyncResult)
    {
        int length = _socket.EndSend(asyncResult);
    }
    public static byte[] Decode(ref List<byte> cache)
    {
        if (cache.Count < 4)
        {
            return null;
        }
        MemoryStream ms = new MemoryStream(cache.ToArray());
        BinaryReader br = new BinaryReader(ms);
        int length = br.ReadInt32();
        if (length > ms.Length - ms.Position)
        {
            return null;
        }
        byte[] buffer = new byte[length];
        buffer = br.ReadBytes(buffer.Length);
        cache.Clear();
        cache.AddRange(br.ReadBytes((int)(ms.Length - ms.Position)));
        ms.Close();
        br.Close();
        return buffer;
    }
}
